package gee

import (
	"log"
	"net/http"
	"strings"
)

type router struct {
	handlers map[string]HandlerFunc // url 对应的handler
	roots    map[string]*node       // 按照请求的方法(GET, POST, HEAD...)不同, 分为不同的trie
}

func newRouter() *router {
	return &router{
		handlers: make(map[string]HandlerFunc),
		roots:    make(map[string]*node),
	}
}

func parsePattern(pattern string) []string {
	vs := strings.Split(pattern, "/")
	parts := make([]string, 0)
	for _, item := range vs {
		if item != "" {
			parts = append(parts, item)
			if item[0] == '*' {
				break
			}
		}
	}
	return parts
}

func (r *router) addRoute(method string, pattern string, handler HandlerFunc) {
	key := method + "-" + pattern

	// 记得给map的节点初始化
	if _, ok := r.roots[method]; !ok {
		r.roots[method] = &node{}
	}

	// 检查是否插入成功
	if ok := r.roots[method].insert(pattern); !ok {
		log.Printf("url conflict %4s - %s", method, pattern)
		return
	}
	// 插入无误添加对应handler
	r.handlers[key] = handler
}

func (r *router) getRoute(method string, path string) (*node, map[string]string) {
	params := make(map[string]string)
	root, ok := r.roots[method]
	if !ok {
		return nil, nil
	}

	u, ok := root.search(path)

	// 这个也比较简单，就是匹配上了之后一一去找对应的就行，不过这个情况考虑其实不是很够..会有错判的情况
	// 将就着用吧
	//log.Printf("%s %s\n", u.pattern, path)
	if u != nil {
		// 将两边的url按 '/'划分，之后一一对应
		patternSepArr := strings.Split(u.pattern[1:], "/")
		pathSepArr := strings.Split(path[1:], "/")
		for i := range patternSepArr {
			if patternSepArr[i] != "" {
				if patternSepArr[i][0] == ':' {
					params[patternSepArr[i][1:]] = pathSepArr[i]
				}
				if patternSepArr[i][0] == '*' {
					params[patternSepArr[i][1:]] = strings.Join(pathSepArr[i:], "/")
					break
				}
			}

		}
		return u, params
	}
	return nil, nil
}

// 所以我的handler就和博主的不一样了，还是跟之前差不多，毕竟handler只是为了handle request罢了
func (r *router) handle(c *Context) {
	// 所以就要先去对应方法的trie里面去search匹配上的url，之后调用匹配上的url的handler去处理这个request
	u, params := r.getRoute(c.Method, c.Path)
	if u != nil {
		c.Params = params
		key := c.Method + "-" + u.pattern
		c.handlers = append(c.handlers, r.handlers[key])
	} else {
		// 返回 404
		c.handlers = append(c.handlers, func(c *Context) {
			c.String(http.StatusNotFound, "404 NOT FOUND: %s\n", c.Path)
		})
	}
	c.Next()
}
